﻿ 
#include <iostream>
#include <algorithm>
using namespace std;


/*
https://www.papamelon.com/problem/362



有 N 个谷仓，谷仓之间有 M 条待修建的道路，每条道路都有一个修建花费。
贝茜由于被欠薪，心生怨念，准备开始一场报复行动。
她要从 M 条路中，选出一些进行修建，使得满足以下的要求：

修建完毕后，任意两个谷仓都是连通的
修建完毕后，任意两个谷仓之间都不存在环
要求修路花费尽可能的大
现在让我们计算一下，要完成贝茜的计划，最多需要花费多少钱？

输入
第一行两个整数N(2≤N≤1000),M(1≤M≤20000)，表示谷仓和所有待修建的道路数量
接下来 M 行，每行三个整数A,B,C(1≤A,B≤N,1≤C≤100000)，表示A,B 之间的道路，其修建代价为 C
输出
一行，一个整数，表示最大的修建代价
样例 1
输入
5 8
1 2 3
1 3 7
2 3 10
2 4 4
2 5 8
3 4 6
3 5 2
4 5 17
输出
42
*/

const int N = 1010; 
const int M = 20010;
//long long INF = 0x3f3f3f3f3f3f;
int p[N];

struct Edge
{
	int a, b, w;

	bool operator< (const Edge &W)const
	{
		return w > W.w;
	}
}edges[M];

int find(int x)
{
	if (p[x] != x) p[x] = find(p[x]);
	return p[x];
}
int n, m;
long long kruskal()
{
	sort(edges, edges + m);

	for (int i = 1; i <N; i++) p[i] = i;    // 初始化并查集

	long long res = 0, cnt = 0;
	for (int i = 0; i < m; i++)
	{
		int a = edges[i].a, b = edges[i].b, w = edges[i].w;

		a = find(a), b = find(b);
		if (a != b)
		{
			p[a] = b;
			res += w;
			cnt++;
		}
	}

	if (cnt < n - 1) return -1;
	return res;
}


int main()
{
	cin >> n >> m;

	for (int i = 0; i < m; i++) {
		int a, b, w;
		cin >> a >> b >> w;
		edges[i].a = a; edges[i].b = b; edges[i].w = w;   
	}

	long long t = kruskal();
	if (t == -1) cout << -1 << endl;
	else {
		cout << t << endl;
	}

	return 0;
}
 